/**
 * @author Fang Lu, fanglupku@gmail.com
 * 2011-4-7
 */
package persist;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Properties;

import code.extract.BasePageDealer;
import code.extract.CEConfig;
import code.extract.PageClassifier;

import com.sleepycat.je.Cursor;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Durability;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.Transaction;

import dao.entity.PageEntity;

public class RefPageDB {
	private Environment env;
	private Database db;
	private long cacheSize = 1024 * 1024;
	private String DBName = null;
	private String encode = null;
	private Cursor insideCursor = null;
	public static void main(String args[]){
		RefPageDB refDB = new RefPageDB(CEConfig.getRefPageBDBDirname(), 1024*1024, "utf8");
		refDB.open(CEConfig.getRefPageBDBDatabasename());
		try {
			System.out.println(refDB.get("http://stderr.org/doc/gij-4.1/html/org/omg/CORBA/UShortSeqHolder-source.html"));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		refDB.close();
	}
	
	public boolean openCursor(){
		try{
			insideCursor = db.openCursor(null, null);
		}catch (DatabaseException de) {
			de.printStackTrace();
			return false;
		}
		return true;
	}
	
	public PageEntity getNextPage() throws UnsupportedEncodingException{
		DatabaseEntry foundKey = new DatabaseEntry();
	    DatabaseEntry foundData = new DatabaseEntry();
	    if (insideCursor.getPrev(foundKey, foundData, LockMode.DEFAULT)
			       == OperationStatus.SUCCESS){
	    	String pageContent = new String(foundData.getData(), encode);
	    	String link = new String(foundKey.getData(), encode);
	    	
	    	ArrayList<String> titleList = BasePageDealer.extractOneTagContent(pageContent, "title");
	    	String title = "";
	    	if (titleList.size() > 0){
	    		title = titleList.get(0);
	    		title = BasePageDealer.eraseAllTags(title);
	    	}
	    	ArrayList<String> metaList = BasePageDealer.extractOneTagContent(pageContent, "meta", "name", "description");
	    	String meta_desc = "";
	    	if (metaList.size() > 0){
	    		meta_desc = metaList.get(0);
	    		meta_desc = BasePageDealer.extractAttribute(meta_desc, "content");
	    	}
	    	metaList = BasePageDealer.extractOneTagContent(pageContent, "meta", "name", "keywords");
	    	String meta_keywords = "";
	    	if (metaList.size() > 0){
	    		meta_keywords = metaList.get(0);
	    		meta_keywords = BasePageDealer.extractAttribute(meta_keywords, "content");
	    	}
	    	PageEntity thisEntity = new PageEntity(-1, link, title, meta_desc, 
	    			meta_keywords, pageContent, PageClassifier.NORMAL_TYPE, PageEntity.CRAWLED_OK);
	    	return thisEntity;
	    }else {
	    	return null;
	    }
	}
	
	public boolean closeCursor(){
		try{
			insideCursor.close();
		}catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	public HashSet<String> getAllCrawledURLSet(){
		HashSet<String> result = new HashSet<String>();
		Cursor cursor = null;
		try {
		    cursor = db.openCursor(null, null);
		    DatabaseEntry foundKey = new DatabaseEntry();
		    DatabaseEntry foundData = new DatabaseEntry();

		    while (cursor.getPrev(foundKey, foundData, LockMode.DEFAULT)
		       == OperationStatus.SUCCESS) {
		        try {
					String theKey = new String(foundKey.getData(), encode);
					result.add(theKey);
//					String theData = new String(foundData.getData(), encode);
				} catch (UnsupportedEncodingException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		    }
		} catch (DatabaseException de) {
		    System.err.println("Error accessing database." + de);
		} finally {
		    cursor.close();
		}
		return result;
	}
	
	public RefPageDB(String path, long cacheSize, String encode) {
		EnvironmentConfig envConfig = new EnvironmentConfig();
		envConfig.setAllowCreate(true);
		envConfig.setCacheSize(cacheSize);
		envConfig.setTransactional(true);
		envConfig.setDurability(Durability.COMMIT_SYNC);    
		
		try {
			File path_file = new File(path);
			if (path_file.exists() == false){
				path_file.mkdirs();
			}
			env = new Environment(path_file, envConfig);
			this.setCacheSize(cacheSize);
			if (encode == null) {
				Properties initProp = new Properties(System.getProperties());
				this.encode = initProp.getProperty("file.encoding");
			} else {
				this.encode = encode;
			}
		} catch (DatabaseException e) {
			e.printStackTrace();
		}
	}

	public void open(String dbName) {
		DatabaseConfig dbConfig = new DatabaseConfig();
		dbConfig.setAllowCreate(true);
		dbConfig.setTransactional(true);
		
		try {
			db = env.openDatabase(null, dbName, dbConfig);
			setDBName(dbName);
		} catch (DatabaseException e) {
			e.printStackTrace();
		}
	}
	
	public void sync() {
		db.sync();
	}

	public void close() {
		try {
			if (db != null) {
				db.close();
			}
			if (env != null) {
				env.cleanLog();
				env.close();
			}
		} catch (DatabaseException e) {
			e.printStackTrace();
		}
	}
	/**
	 * @param key(should be a class name or other keywords)
	 * @return
	 * @throws Exception
	 */
	public String get(String key) throws Exception {
		DatabaseEntry queryKey = new DatabaseEntry();
		DatabaseEntry value = new DatabaseEntry();
		queryKey.setData(key.getBytes(encode));
		OperationStatus status = db
				.get(null, queryKey, value, LockMode.DEFAULT);
		if (status == OperationStatus.SUCCESS) {
			return new String(value.getData());
		}
		return null;
	}
	/**
	 * @param key(should be a class name or other keywords)
	 * @param value(should be a google result page)
	 * @return
	 * @throws Exception
	 */
	public boolean put(String key, String value) throws Exception {
		byte[] theKey = key.getBytes(encode);
		byte[] theValue = value.getBytes(encode);
		Transaction txn = env.beginTransaction(null, null);
		OperationStatus status = db.put(txn, new DatabaseEntry(theKey),
				new DatabaseEntry(theValue));
		txn.commit();
		if (status == OperationStatus.SUCCESS) {
			return true;
		}
		return false;
	}

	public void setCacheSize(long cacheSize) {
		this.cacheSize = cacheSize;
	}

	public long getCacheSize() {
		return cacheSize;
	}

	public void setDBName(String dBName) {
		DBName = dBName;
	}

	public String getDBName() {
		return DBName;
	}
	
}
